package org.example.hotel.service;

import org.example.hotel.config.SystemStatus;
import org.example.hotel.entity.Room;
import org.example.hotel.entity.Room.WindSpeed;
import org.example.hotel.entity.UsageRecord;
import org.example.hotel.repository.UsageRecordRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.example.hotel.repository.RoomRepository;

import jakarta.annotation.PostConstruct;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class ScheduleService {

    private static final int MAX_SERVING_ROOMS = 3;
    private static final int TIME_SLICE_SECONDS = 120;
    private static final double RESTART_TEMP_DIFFERENCE = 1.0;

    private static final int TEMP_CHANGE_INTERVAL_SECONDS = 1;
    private static final double TEMP_CHANGE_PER_MINUTE = 0.5;

    private static final double DEFAULT_TEMP_CHANGE_RATE = TEMP_CHANGE_PER_MINUTE / (60.0 / TEMP_CHANGE_INTERVAL_SECONDS);


    private final Set<Integer> servingList = new HashSet<>();
    private final Queue<Integer> waitingQueue = new LinkedList<>();
    private final Map<Integer, LocalDateTime> acStartTimeMap = new ConcurrentHashMap<>();


    @Autowired
    private RoomRepository roomRepository;

    @Autowired
    private UsageRecordRepository usageRecordRepository;

    @Autowired
    private SystemStatus systemStatus;

    @PostConstruct
    public void initializeServingState() {
        List<Room> rooms = roomRepository.findAll();
        for (Room room : rooms) {
            if (room.isServing()) {
                servingList.add(room.getRoomId());
            }
            /*if (room.isWaiting()) {
                waitingQueue.add(room.getRoomId());
            }*/
        }

        System.out.println("[系统初始化] ServingList状态同步完成");
    }

    @Transactional
    public void processWindRequest(int roomId, WindSpeed newSpeed) {
        if (!systemStatus.isSystemRunning()) return;

        Room room = roomRepository.findById(roomId).orElse(null);
        if (room == null || room.isDebounced()) return;

        room.recordSpeedChangeTime();

        if (newSpeed != room.getWindSpeedEnum()) {
            room.setFanSpeed(newSpeed.name());
        }
        room.refreshServiceTime();
        roomRepository.save(room);

        applySchedulingPolicy(roomId);
    }

    @Transactional
    public synchronized void applySchedulingPolicy(int roomId) {
        if (!systemStatus.isSystemRunning()) return;

        Room requestRoom = roomRepository.findById(roomId).orElse(null);
        if (requestRoom == null || !requestRoom.isAcOn()) return;

        WindSpeed requestSpeed = requestRoom.getWindSpeedEnum();
        int requestPriority = requestSpeed.getPriority();

        // 已经在服务中
        if (servingList.contains(roomId)) {
            requestRoom.refreshServiceTime();
            requestRoom.setServing(true);
            roomRepository.save(requestRoom);
            return;
        }

        // 服务对象未满，直接分配
        if (servingList.size() < MAX_SERVING_ROOMS) {
            assignService(requestRoom);
            return;
        }

        // 服务已满，查找优先级低的服务对象
        List<Room> lowerPriorityRooms = servingList.stream()
                .map(id -> roomRepository.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .filter(r -> r.getWindSpeedEnum().getPriority() < requestPriority)
                .toList();

        if (!lowerPriorityRooms.isEmpty()) {
            Room toRelease = lowerPriorityRooms.stream()
                    .collect(Collectors.groupingBy(
                            Room::getWindSpeedEnum,
                            Collectors.collectingAndThen(
                                    Collectors.toList(),
                                    list -> list.stream()
                                            .max(Comparator.comparingLong(Room::getServiceDuration))
                                            .orElse(null)
                            )
                    )).values().stream()
                    .min(Comparator.comparingInt(r -> r.getWindSpeedEnum().getPriority()))
                    .orElse(null);

            if (toRelease != null) {
                releaseService(toRelease.getRoomId(), true);
                assignService(requestRoom);
                return;
            }
        }

        // 优先级相同，走时间片调度
        if (!waitingQueue.contains(roomId)) {
            requestRoom.startWaiting(); // 记录等待时间戳
            roomRepository.save(requestRoom);
            waitingQueue.add(roomId);
        }
    }

    @Transactional
    public void assignService(Room room) {
        int roomId = room.getRoomId();

        if (!room.isAcOn()) {
            System.out.printf("[%s] 房间 #%d 空调未开启，跳过分配送风\n",
                    Thread.currentThread().getName(), roomId);
            return;
        }

        System.out.printf("[%s] assignService() 开始，房间 #%d 被请求送风，当前 servingList = %s\n",
                Thread.currentThread().getName(), roomId, servingList);

        room.setServing(true);
        room.refreshServiceTime();

        waitingQueue.remove(room.getRoomId());
        room.clearWaitStartTime();
        servingList.add(roomId);

        LocalDateTime startTime = LocalDateTime.now();
        acStartTimeMap.put(roomId, startTime);
        roomRepository.save(room);

    }

    @Transactional
    public void releaseService(int roomId, boolean requeue) {
        Room room = roomRepository.findById(roomId).orElse(null);
        if (room == null) return;

        // === 1. 生成使用记录 ===
        LocalDateTime startTime = acStartTimeMap.remove(roomId);
        if (startTime != null) {
            LocalDateTime now = LocalDateTime.now();

            UsageRecord record = new UsageRecord();
            record.setRoomId(roomId);
            record.setFanSpeed(room.getFanSpeed());
            record.setStartTime(startTime);
            record.setEndTime(now);
            record.setDurationSeconds(Duration.between(startTime, now).getSeconds());
            record.calculateCost();

            usageRecordRepository.save(record);
            System.out.printf("房间 #%d 停止送风，保存使用记录，费用=%.2f\n", roomId, record.getCost());
        }

        // === 2. 正常释放服务 ===
        room.setServing(false);
        servingList.remove(roomId);

        if (requeue) {
            room.startWaiting();
            waitingQueue.add(roomId);
        }

        roomRepository.save(room);
    }

    @Transactional
    public synchronized void rescheduleRooms() {
        List<Integer> toRelease = new ArrayList<>();
        List<Room> toAssign = new ArrayList<>();
        List<Integer> toRemoveFromWaiting = new ArrayList<>();

        Iterator<Integer> iterator = waitingQueue.iterator();

        while (iterator.hasNext()) {
            int candidateId = iterator.next();
            Room candidate = roomRepository.findById(candidateId).orElse(null);
            if (candidate == null) {
                toRemoveFromWaiting.add(candidateId);
                continue;
            }

            WindSpeed candidateSpeed = candidate.getWindSpeedEnum();
            Long waitDuration = candidate.getWaitDuration();
            if (waitDuration == null) continue;

            if (waitDuration >= TIME_SLICE_SECONDS * 1000) {
                List<Room> sameSpeedRooms = servingList.stream()
                        .map(id -> roomRepository.findById(id).orElse(null))
                        .filter(Objects::nonNull)
                        .filter(r -> r.getWindSpeedEnum() == candidateSpeed)
                        .toList();

                if (!sameSpeedRooms.isEmpty()) {
                    Room longestServing = sameSpeedRooms.stream()
                            .max(Comparator.comparingLong(Room::getServiceDuration))
                            .orElse(null);

                    if (longestServing != null) {
                        toRelease.add(longestServing.getRoomId());
                        toAssign.add(candidate);
                        toRemoveFromWaiting.add(candidateId);
                    } else {
                        // 没抢到机会，重置等待时间
                        candidate.startWaiting();
                        roomRepository.save(candidate);
                    }
                } else {
                    // 同风速服务对象为空，也重置等待
                    candidate.startWaiting();
                    roomRepository.save(candidate);
                }
            }

        }

        // 执行释放操作
        for (int releaseId : toRelease) {
            releaseService(releaseId, true);
        }

        // 执行分配操作
        for (Room r : toAssign) {
            assignService(r);
        }

        // 移除已分配或失效的房间ID
        waitingQueue.removeAll(toRemoveFromWaiting);

        // 补齐剩余空位
        while (servingList.size() < MAX_SERVING_ROOMS && !waitingQueue.isEmpty()) {
            int nextId = waitingQueue.poll();
            Room room = roomRepository.findById(nextId).orElse(null);
            if (room != null) {
                assignService(room);
            }
        }
    }

    @Transactional
    public synchronized void simulateTemperatureChange() {
        List<Room> allRooms = roomRepository.findAll();

        System.out.println("[定时任务] simulateTemperatureChange() 开始执行");
        System.out.println("当前送风房间 ID：" + servingList);
        System.out.println("---------------------------------------------------");

        for (Room room : allRooms) {
            int roomId = room.getRoomId();
            boolean isServing = servingList.contains(roomId);
            double ambientTemp = room.getInitialTemp();
            double currentTemp = room.getCurrentTemp();
            double targetTemp = room.getTargetTemp();
            double changeRate = DEFAULT_TEMP_CHANGE_RATE;

            //System.out.printf("房间 #%d | 当前=%.2f°C, 目标=%.2f°C, 差值=%.4f, 送风中=%s, room.serving=%s, 模式=%s\n",
            //       roomId, currentTemp, targetTemp, Math.abs(currentTemp - targetTemp), isServing, room.isServing(), room.getWorkMode());

            if (isServing) {
                // 根据风速调整温度变化速率
                switch (room.getWindSpeedEnum()) {
                    case HIGH -> changeRate *= 1.2;
                    case LOW -> changeRate *= 0.8;
                    default -> {}
                }

                if (Math.abs(currentTemp - targetTemp) < 0.05) {
                    // 达到目标温度，停止送风
                    releaseService(roomId, false);
                    System.out.printf("房间 #%d 已达到目标温度，停止送风，温度=%.2f\n", roomId, currentTemp);
                } else {
                    // 按照工作模式升温或降温
                    if (room.getWorkMode().equals("COLD")) {
                        double newTemp = Math.max(targetTemp, currentTemp - changeRate);
                        room.setCurrentTemp(newTemp);
                        //System.out.printf("房间 #%d 制冷中，%.2f → %.2f\n", roomId, currentTemp, newTemp);
                    } else if (room.getWorkMode().equals("HOT")) {
                        double newTemp = Math.min(targetTemp, currentTemp + changeRate);
                        room.setCurrentTemp(newTemp);
                        //System.out.printf("房间 #%d 制热中，%.2f → %.2f\n", roomId, currentTemp, newTemp);
                    }
                }
            } else {
                // 非送风状态下温度变化与重新调度
                boolean needRestart = false;

                if (room.isAcOn() && room.getWorkMode().equals("COLD") && currentTemp >= targetTemp + RESTART_TEMP_DIFFERENCE) {
                    needRestart = true;
                } else if (room.isAcOn() && room.getWorkMode().equals("HOT") && currentTemp <= targetTemp - RESTART_TEMP_DIFFERENCE) {
                    needRestart = true;
                }

                if (needRestart) {
                    //System.out.printf("房间 #%d 温度偏离目标超过 %.1f°C，重新请求送风\n", roomId, RESTART_TEMP_DIFFERENCE);
                    applySchedulingPolicy(roomId);
                } else {
                    // 温度缓慢回弹（靠外部环境）
                    if (currentTemp < ambientTemp) {
                        double newTemp = Math.min(ambientTemp, currentTemp + DEFAULT_TEMP_CHANGE_RATE);
                        room.setCurrentTemp(newTemp);
                        //System.out.printf("房间 #%d 温度回弹上升 %.2f → %.2f（向初始室温 %.2f 回弹）\n", roomId, currentTemp, newTemp, ambientTemp);
                    } else {
                        double newTemp = Math.max(ambientTemp, currentTemp - DEFAULT_TEMP_CHANGE_RATE);
                        room.setCurrentTemp(newTemp);
                        //System.out.printf("房间 #%d 温度回弹下降 %.2f → %.2f（向初始室温 %.2f 回弹）\n", roomId, currentTemp, newTemp, ambientTemp);
                    }
                }
            }

            // 确保数据库 serving 字段与内存状态一致
            if (room.isAcOn() && room.isServing() != isServing) {
                //System.out.printf("房间 #%d serving 状态不同步：内存=%s, 数据库=%s → 更新数据库\n",
                //        roomId, isServing, room.isServing());
                room.setServing(isServing);
            }

            roomRepository.save(room);
        }

        //System.out.println("[定时任务] simulateTemperatureChange() 执行完毕");
        //System.out.println("---------------------------------------------------\n");
    }


    public List<Room> getCurrentServingRooms() {
        return roomRepository.findAllById(servingList);
    }


    public List<Room> getCurrentWaitingRooms() {
        List<Integer> ids = new ArrayList<>(waitingQueue);
        Map<Integer, Room> roomMap = roomRepository.findAllById(ids).stream()
                .collect(Collectors.toMap(Room::getRoomId, r -> r));

        return ids.stream()
                .map(roomMap::get)
                .filter(Objects::nonNull)
                .toList();
    }

    @Transactional
    public synchronized void releaseRoom(int roomId) {
        releaseService(roomId, false);  // 标准释放 + 保存记录
        waitingQueue.remove(roomId);    // 只额外移除 waitingQueue 中残留项（保险）

        Room room = roomRepository.findById(roomId).orElse(null);
        if (room == null) return;

        room.clearServiceState();       // 清除标志位
        roomRepository.save(room);

        /*if (room.isAcOn()) {
            applySchedulingPolicy(roomId); // 如果空调还开着，可以重新调度
        }*/
    }

    public UsageRecord getLiveUsagePreview(int roomId) {
        Room room = getRoom(roomId);
        LocalDateTime startTime = acStartTimeMap.get(roomId);
        LocalDateTime now = LocalDateTime.now();

        if (!room.isAcOn() || !room.isServing() || startTime == null || startTime.isAfter(now)) {
            return null;
        }

        UsageRecord record = new UsageRecord();
        record.setRoomId(roomId);
        record.setFanSpeed(room.getFanSpeed());
        record.setStartTime(startTime);
        record.setEndTime(now);
        record.setDurationSeconds(Duration.between(startTime, now).getSeconds());
        record.calculateCost();

        return record;
    }

    private Room getRoom(int roomId) {
        return roomRepository.findById(roomId)
                .orElseThrow(() -> new RuntimeException("房间不存在"));
    }

}


